package it.bela.pgcdc.controller;

import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Collection;
import java.util.Date;
import java.util.HashSet;
import java.util.List;

import it.bela.pgcdc.common.utils.Constants;
import it.bela.pgcdc.domain.Attivita;
import it.bela.pgcdc.domain.Contatto;
import it.bela.pgcdc.domain.Hobby;
import it.bela.pgcdc.domain.Lavoro;
import it.bela.pgcdc.domain.MailingList;
import it.bela.pgcdc.domain.Parrocchia;
import it.bela.pgcdc.domain.Preferenza;

import it.bela.pgcdc.domain.references.StatoCivileType;

import it.bela.pgcdc.editor.AttivitaPropertyEditor;
import it.bela.pgcdc.editor.HobbyPropertyEditor;
import it.bela.pgcdc.editor.LavoroPropertyEditor;
import it.bela.pgcdc.editor.MaililngListPropertyEditor;
import it.bela.pgcdc.editor.ParrocchiaPropertyEditor;
import it.bela.pgcdc.editor.PreferenzaPropertyEditor;
import it.bela.pgcdc.service.AttivitaService;
import it.bela.pgcdc.service.ContattoService;
import it.bela.pgcdc.service.HobbyService;
import it.bela.pgcdc.service.LavoroService;
import it.bela.pgcdc.service.MailingListService;
import it.bela.pgcdc.service.ParrocchiaService;
import it.bela.pgcdc.service.PreferenzaService;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;

import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.propertyeditors.CustomDateEditor;
import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.support.SessionStatus;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.view.RedirectView;

@Controller
public class ContattoController {

	private static final Logger log = Logger.getLogger(ContattoController.class);

	@Autowired(required = true)
	private ContattoService contattoService;

	@Autowired(required = true)
	private PreferenzaService preferenzaService;

	@Autowired(required = true)
	private LavoroService lavoroService;

	@Autowired(required = true)
	private ParrocchiaService parrocchiaService;

	@Autowired(required = true)
	private AttivitaService attivitaService;

	@Autowired(required = true)
	private HobbyService hobbyService;

	@Autowired(required = true)
	private MailingListService mailingListService;

	@ModelAttribute("contatto")
	public Contatto populateContatto() throws Exception {
		try{

			return new Contatto();
		}
		catch (Exception e) {
			e.printStackTrace();
			log.error("view - Errore durante la visualizzazione Contatto - " + e);
			throw new Exception(Constants.POPULATE_MODEL_ERROR_KEY, e);
		}
	}

	@ModelAttribute("statociviletypes")
	public Collection<StatoCivileType> populateStatoCivileTypes() {
		return Arrays.asList(StatoCivileType.class.getEnumConstants());
	}

	@ModelAttribute("lavoroList")
	public List<Lavoro> populateLavoroList() throws Exception {
		try{

			List<Lavoro> lavoroList = lavoroService.list();
			return lavoroList;
		}
		catch (Exception e) {
			e.printStackTrace();
			log.error("view - Errore durante la visualizzazione Contatto - " + e);
			throw new Exception(Constants.POPULATE_MODEL_ERROR_KEY, e);
		}
	}

	@ModelAttribute("parrocchiaList")
	public List<Parrocchia> populateParrocchiaList() throws Exception {
		try{

			List<Parrocchia> parrocchiaList = parrocchiaService.list();
			return parrocchiaList;
		}
		catch (Exception e) {
			e.printStackTrace();
			log.error("view - Errore durante la visualizzazione Contatto - " + e);
			throw new Exception(Constants.POPULATE_MODEL_ERROR_KEY, e);
		}
	}

	@ModelAttribute("preferenzaList")
	public List<Preferenza> populatePreferenzaList() throws Exception {
		try{

			List<Preferenza> preferenzaList = preferenzaService.list();
			return preferenzaList;
		}
		catch (Exception e) {
			e.printStackTrace();
			log.error("view - Errore durante la visualizzazione Contatto - " + e);
			throw new Exception(Constants.POPULATE_MODEL_ERROR_KEY, e);
		}
	}

	@ModelAttribute("attivitaList")
	public List<Attivita> populateAttivitaList() throws Exception {
		try{

			List<Attivita> attivitaList = attivitaService.list();
			return attivitaList;
		}
		catch (Exception e) {
			e.printStackTrace();
			log.error("view - Errore durante la visualizzazione Contatto - " + e);
			throw new Exception(Constants.POPULATE_MODEL_ERROR_KEY, e);
		}
	}

	@ModelAttribute("hobbyList")
	public List<Hobby> populatHobbyList() throws Exception {
		try{

			List<Hobby> hobbyList = hobbyService.list();
			return hobbyList;
		}
		catch (Exception e) {
			e.printStackTrace();
			log.error("view - Errore durante la visualizzazione Contatto - " + e);
			throw new Exception(Constants.POPULATE_MODEL_ERROR_KEY, e);
		}
	}

	@ModelAttribute("mailingListList")
	public List<MailingList> populatMailingListList() throws Exception {
		try{

			List<MailingList> mailingListList = mailingListService.list();
			return mailingListList;
		}
		catch (Exception e) {
			e.printStackTrace();
			log.error("view - Errore durante la visualizzazione Contatto - " + e);
			throw new Exception(Constants.POPULATE_MODEL_ERROR_KEY, e);
		}
	}

	@RequestMapping(value = "saveContatto.htm", method = RequestMethod.POST)
	public ModelAndView saveContatto(@ModelAttribute("contatto") @Valid Contatto contatto,
			BindingResult errors, SessionStatus status, HttpServletRequest request, HttpServletResponse res) throws Exception {

		try{

			log.debug("Start view saveContatto");

			ModelAndView mav = new ModelAndView(Constants.TILES_KEY_FORM_CONTATTO);

			if (errors.hasErrors()){
				mav.addAllObjects(errors.getModel());

				log.debug("End saveContatto with errors");
				return mav;
			}

			if (contatto.getAltraParrocchia() != null && !contatto.getAltraParrocchia().equals("")){
				Parrocchia parrocchia = new Parrocchia();
				parrocchia.setDescrizione(contatto.getAltraParrocchia());
				
				List<Parrocchia> parrocchiaList = parrocchiaService.findByExample(parrocchia);
				if (parrocchiaList.isEmpty()){
					parrocchiaService.save(parrocchia);
				} else{
					parrocchia = parrocchiaList.get(0);
				}
				
				contatto.setParrocchia(parrocchia);
			}

			if (contatto.getAltroLavoro() != null && !contatto.getAltroLavoro().equals("")){
				Lavoro lavoro = new Lavoro();
				lavoro.setDescrizione(contatto.getAltroLavoro());

				List<Lavoro> lavoroList = lavoroService.findByExample(lavoro);
				if (lavoroList.isEmpty()){
					lavoroService.save(lavoro);
				} else{
					lavoro = lavoroList.get(0);
				}

				contatto.setLavoro(lavoro);
			}

			if (contatto.getAltraPreferenza() != null && !contatto.getAltraPreferenza().equals("")){
				Preferenza preferenza = new Preferenza();
				preferenza.setDescrizione(contatto.getAltraPreferenza());

				List<Preferenza> preferenzaList = preferenzaService.findByExample(preferenza);
				if (preferenzaList.isEmpty()){
					preferenzaService.save(preferenza);
				} else{
					preferenza = preferenzaList.get(0);
				}

				if (contatto.getPreferenze() == null)
					contatto.setPreferenze(new HashSet<Preferenza>());

				contatto.getPreferenze().add(preferenza);
			}

			if (contatto.getAltraAttivita() != null && !contatto.getAltraAttivita().equals("")){
				Attivita attivita = new Attivita();
				attivita.setDescrizione(contatto.getAltraAttivita());

				List<Attivita> attivitaList = attivitaService.findByExample(attivita);
				if (attivitaList.isEmpty()){
					attivitaService.save(attivita);
				} else{
					attivita = attivitaList.get(0);
				}
				
				if (contatto.getAttivita() == null)
					contatto.setAttivita(new HashSet<Attivita>());

				contatto.getAttivita().add(attivita);
			}

			if (contatto.getAltroHobby() != null && !contatto.getAltroHobby().equals("")){
				Hobby hobby = new Hobby();
				hobby.setDescrizione(contatto.getAltroHobby());

				List<Hobby> hobbyList = hobbyService.findByExample(hobby);
				if (hobbyList.isEmpty()){
					hobbyService.save(hobby);
				} else{
					hobby = hobbyList.get(0);
				}

				if (contatto.getHobbies() == null)
					contatto.setHobbies(new HashSet<Hobby>());

				contatto.getHobbies().add(hobby);
			}

			if (contatto.getId() == null)
				contattoService.save(contatto);
			else 
				contattoService.merge(contatto);

			log.debug("End view saveContatto");

			return new ModelAndView(new RedirectView(Constants.HOME_VIEW_PAGE));
		}
		catch (Exception e) {
			e.printStackTrace();
			log.error("view - Errore durante il salvataggio - " + e);
			throw new Exception(Constants.SAVE_OBJECT_ERROR_KEY, e);
		}
	}

	@RequestMapping(value = "editContatto.htm", method = RequestMethod.GET)
	public ModelAndView editContatto(@ModelAttribute("contatto") Contatto contatto,
			BindingResult errors, SessionStatus status, ModelMap modelMap, HttpServletRequest request, HttpServletResponse res) throws Exception {

		try{

			log.debug("Start view editContatto");

			ModelAndView mav = new ModelAndView(Constants.TILES_KEY_FORM_CONTATTO);

			contatto = (Contatto) contattoService.findById(Contatto.class, contatto.getId());

			modelMap.put("contatto", contatto);

			log.debug("End view editContatto");

			return mav;
		}
		catch (Exception e) {
			e.printStackTrace();
			log.error("view - Errore durante la visualizzazione del form - " + e);
			throw new Exception(Constants.EDIT_OBJECT_ERROR_KEY, e);
		}
	}

	@RequestMapping(value = "newContatto.htm", method = RequestMethod.GET)
	public ModelAndView newContatto(HttpServletRequest request, HttpServletResponse res) throws Exception {

		try{

			log.debug("Start view newContatto");

			ModelAndView mav = new ModelAndView(Constants.TILES_KEY_FORM_CONTATTO);

			log.debug("End view newContatto");

			return mav;
		}
		catch (Exception e) {
			e.printStackTrace();
			log.error("view - Errore durante la visualizzazione del form - " + e);
			throw new Exception(Constants.EDIT_OBJECT_ERROR_KEY, e);
		}
	}

	@RequestMapping(value = "deleteContatto.htm")
	public ModelAndView deleteContatto(@ModelAttribute("contatto") Contatto contatto,
			BindingResult errors, SessionStatus status, HttpServletRequest request, HttpServletResponse res) throws Exception {

		try{

			log.debug("Start view deleteContatto");

			contattoService.delete(contatto);

			log.debug("End view deleteContatto");

			return new ModelAndView(new RedirectView(Constants.HOME_VIEW_PAGE));
		}
		catch (Exception e) {
			e.printStackTrace();
			log.error("view - Errore durante la cancellazione - " + e);
			throw new Exception(Constants.DELETE_OBJECT_ERROR_KEY, e);
		}
	}

	@InitBinder
	public void initBinder(WebDataBinder binder) {

		CustomDateEditor editorDate = new CustomDateEditor(new SimpleDateFormat("dd/MM/yyyy", LocaleContextHolder.getLocale()), true);	
		binder.registerCustomEditor(Date.class, editorDate);

		ParrocchiaPropertyEditor parrocchiaPropertyEditor = new ParrocchiaPropertyEditor(parrocchiaService);
		binder.registerCustomEditor(Parrocchia.class, parrocchiaPropertyEditor);

		LavoroPropertyEditor lavoroPropertyEditor = new LavoroPropertyEditor(lavoroService);
		binder.registerCustomEditor(Lavoro.class, lavoroPropertyEditor);

		PreferenzaPropertyEditor preferenzaPropertyEditor = new PreferenzaPropertyEditor(preferenzaService);
		binder.registerCustomEditor(Preferenza.class, preferenzaPropertyEditor);

		AttivitaPropertyEditor attivitaPropertyEditor = new AttivitaPropertyEditor(attivitaService);
		binder.registerCustomEditor(Attivita.class, attivitaPropertyEditor);

		HobbyPropertyEditor hobbyPropertyEditor = new HobbyPropertyEditor(hobbyService);
		binder.registerCustomEditor(Hobby.class, hobbyPropertyEditor);

		MaililngListPropertyEditor maililngListPropertyEditor = new MaililngListPropertyEditor(mailingListService);
		binder.registerCustomEditor(MailingList.class, maililngListPropertyEditor);
	}
}
